/**
 * 
 */
package wpmp.security.mgr.service;

import java.sql.Timestamp;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.hibernate.Criteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.type.StandardBasicTypes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import wcommons.lang.DateUtils;
import wcommons.lang.NumberUtils;
import wcommons.lang.quickbean.Message;
import wpmp.security.mgr.base.BaseService;
import wpmp.security.mgr.dao.OperationDao;
import wpmp.security.mgr.entity.Operation;

/**
 * @author Wayne.Wang<5waynewang@gmail.com>
 * @since 2:41:58 PM Mar 18, 2013
 */
@Component
@Transactional(rollbackFor = Exception.class)
public class OperationService extends BaseService {

	private static final String SQL_EXISTS_RESOURCE = "EXISTS(SELECT 1 FROM sys_resource_operation_rela WHERE operation_id={alias}.id AND resource_id=?)";

	private static final Logger LOG = LoggerFactory.getLogger(OperationService.class);

	// 需要更新的字段
	private static final String[] UPDATE_PROPERTIES = { "name", "value", "memo" };

	private OperationDao dao;

	@Autowired
	public void setDao(OperationDao dao) {
		this.dao = dao;
	}

	public Operation get(Long id) {
		Operation entity = dao.get(id);
		if (entity == null) {
			return entity;
		}
		Operation result = new Operation();
		BeanUtils.copyProperties(entity, result);
		return result;
	}

	public List<Operation> getResourceOperations(Long resourceId) {
		Criteria criteria = dao.createCriteria(Restrictions.sqlRestriction(SQL_EXISTS_RESOURCE, resourceId,
				StandardBasicTypes.LONG));
		criteria.addOrder(Order.asc("orderNum"));
		return dao.queryForList(criteria);
	}

	public int count() {
		return dao.queryForInt();
	}

	public List<Operation> list() {
		return dao.queryForList(Order.asc("orderNum"));
	}

	public Message validateName(Operation entity) {
		Criteria criteria = dao.createCriteria(Restrictions.eq("name", entity.getName()));
		if (NumberUtils.gtZero(entity.getId())) {
			criteria.add(Restrictions.ne("id", entity.getId()));
		}
		if (dao.queryForInt(criteria) > 0) {
			return Message.getErrorMessage("已存在操作名称 [" + entity.getName() + "]");
		}
		return Message.getDefaultMessage();
	}

	public int getMaxOrderNum() {
		Integer maxOrderNum = (Integer) dao.createCriteria().setProjection(Projections.max("orderNum")).uniqueResult();
		return maxOrderNum == null ? 0 : maxOrderNum.intValue();
	}

	public Message insert(Operation entity) {
		Message message = validateName(entity);
		if (message.notpass()) {
			return message;
		}

		Timestamp currentTime = new Timestamp(System.currentTimeMillis());
		entity.setOrderNum(getMaxOrderNum() + 1);
		entity.setCreateTime(currentTime);
		entity.setCreateUser(entity.getSysLoginName());
		entity.setUpdateTime(currentTime);
		entity.setUpdateUser(entity.getSysLoginName());
		dao.save(entity);
		return message;
	}

	public Message update(Operation entity) {
		Message message = validateName(entity);
		if (message.notpass()) {
			return message;
		}

		Operation result = dao.get(entity.getId());

		wcommons.beanutils.BeanUtils.copyProperties(result, entity, UPDATE_PROPERTIES, false);
		result.setUpdateTime(DateUtils.newTimestamp());
		result.setUpdateUser(entity.getSysLoginName());
		dao.save(result);

		return message;
	}

	public Message delete(Long[] ids) {
		if (ArrayUtils.isEmpty(ids)) {
			return Message.getErrorMessage("请选择您要删除的记录");
		}

		// 删除资源、操作类型之间的关系
		dao.deleteResourceOperationRela(ids);
		// 删除角色、资源、操作之间的关系
		dao.deleteRoleResourceOperationRela(ids);
		// 删除操作类型
		dao.delete(ids);

		Criteria criteria = dao.createCriteria(Restrictions.not(Restrictions.in("id", ids)));
		criteria.addOrder(Order.asc("orderNum"));
		List<Operation> entities = dao.queryForList(criteria);
		if (CollectionUtils.isNotEmpty(entities)) {
			for (int i = 0; i < entities.size(); i++) {
				entities.get(i).setOrderNum(i + 1);
			}
			dao.save(entities);
		}
		return Message.getDefaultMessage();
	}

	public Message sort(Long[] ids) {
		Integer[] orderNums = new Integer[ids.length];
		for (int i = 0; i < ids.length; i++) {
			orderNums[i] = i + 1;
		}
		int[] status = dao.updateOrderNum(ids, orderNums);

		if (LOG.isDebugEnabled()) {
			LOG.debug("UPDATE Operation's orderNum: ids[{}], return [{}]", ArrayUtils.toString(ids),
					ArrayUtils.toString(status));
		}

		return Message.getDefaultMessage();
	}
}
